package org.jeecg.modules.demo;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 微信支付服务类
 */
public class WechatPayService {
    private final WechatPayConfig config;
    private final PrivateKey privateKey;
    private final CloseableHttpClient httpClient;

    static {
        // 确保BouncyCastle提供者已注册
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    /**
     * 初始化微信支付服务
     */
    public WechatPayService(WechatPayConfig config) throws Exception {
        this.config = config;

        // 加载商户私钥
        this.privateKey = loadPrivateKey(config.getPrivateKeyFile());

        // 初始化HTTPS客户端
        this.httpClient = createHttpClient();
    }

    /**
     * 加载PEM格式的私钥
     */
    private PrivateKey loadPrivateKey(File privateKeyFile) throws Exception {
        try (PEMParser pemParser = new PEMParser(new FileReader(privateKeyFile))) {
            PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) pemParser.readObject();
            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME);
            return converter.getPrivateKey(privateKeyInfo);
        }
    }

    /**
     * 创建HTTPS客户端，正确处理证书和私钥
     */
    private CloseableHttpClient createHttpClient() throws Exception {
        // 1. 加载证书
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate cert;
        try (FileInputStream fis = new FileInputStream(config.getCertFile())) {
            cert = (X509Certificate) cf.generateCertificate(fis);
        }

        // 2. 创建临时KeyStore
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(null, null); // 初始化空的KeyStore

        // 3. 将证书和私钥存入KeyStore
        keyStore.setCertificateEntry("cert-alias", cert);
        keyStore.setKeyEntry("key-alias", privateKey,
                config.getMchId().toCharArray(), new X509Certificate[]{cert});

        // 4. 初始化密钥管理器
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(
                KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, config.getMchId().toCharArray());

        // 5. 构建SSL上下文
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), null, null);

        // 6. 创建HTTPS客户端
        return HttpClients.custom()
                .setSSLContext(sslContext)
                .build();
    }

    /**
     * 创建JSAPI支付订单
     */
    public JSONObject createJsapiOrder(String outTradeNo, int totalAmount, String description, String openid) throws Exception {
        String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";

        // 构建请求体
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("appid", config.getAppid());
        requestBody.put("mchid", config.getMchId());
        requestBody.put("description", description);
        requestBody.put("out_trade_no", outTradeNo);
        requestBody.put("notify_url", config.getNotifyUrl());

        Map<String, Object> amount = new HashMap<>();
        amount.put("total", totalAmount);
        amount.put("currency", "CNY");
        requestBody.put("amount", amount);

        Map<String, Object> payer = new HashMap<>();
        payer.put("openid", openid);
        requestBody.put("payer", payer);

        String jsonBody = JSONObject.toJSONString(requestBody);

        // 生成签名
        String nonceStr = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
        long timestamp = System.currentTimeMillis() / 1000;
        String signature = generateRequestSignature("POST", "/v3/pay/transactions/jsapi", timestamp, nonceStr, jsonBody);

        // 创建请求
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Content-Type", "application/json");
        httpPost.setHeader("Accept", "application/json");
        httpPost.setHeader("Authorization", buildAuthorizationHeader(nonceStr, timestamp, signature));
        httpPost.setEntity(new StringEntity(jsonBody, "UTF-8"));

        // 发送请求
        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            HttpEntity entity = response.getEntity();
            String responseString = EntityUtils.toString(entity);
            return JSONObject.parseObject(responseString);
        }
    }

    /**
     * 生成请求签名
     */
    private String generateRequestSignature(String method, String urlPath, long timestamp, String nonceStr, String body) throws Exception {
        String signatureStr = String.format("%s\n%s\n%d\n%s\n%s\n",
                method, urlPath, timestamp, nonceStr, body);

        java.security.Signature signature = java.security.Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(signatureStr.getBytes("UTF-8"));
        return java.util.Base64.getEncoder().encodeToString(signature.sign());
    }

    /**
     * 构建Authorization请求头
     */
    private String buildAuthorizationHeader(String nonceStr, long timestamp, String signature) {
        return String.format("WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",signature=\"%s\",timestamp=\"%d\",serial_no=\"%s\"",
                config.getMchId(), nonceStr, signature, timestamp, config.getMchSerialNo());
    }

    /**
     * 关闭资源
     */
    public void close() throws Exception {
        if (httpClient != null) {
            httpClient.close();
        }
    }
}
